<!--
  封装高德地图选址组件
  initMapData: { areacode:[],  areacodeNames:[], address: '', lnglat: '' } //areacode 位置、 省市县名称字符串数组、 详细地址， 经纬度（中间,分割） 
  @author will
  @site https://pt.jdyd.xyz
  @date 2022/05/07 11:34
-->
<template>
  <a-row>
    <a-col :span="12">
      <a-form-item label="选址省/市/区" name="areacode">
        <GzAreaSelect ref="gzAreaSelect" v-model:value="vdata.mapData.areacode" @change="changeAreaCodeFunc" />
      </a-form-item>
    </a-col>
    <a-col :span="12">
      <a-form-item class="right" label="具体位置" name="address">
        <a-input id="amap-search-input" v-model:value="vdata.mapData.address" autoComplete="off" />
      </a-form-item>
    </a-col>
    <a-col :span="12">
      <a-form-item label="经纬度" name="lnglat">
        <a-input v-model:value="vdata.mapData.lnglat" autoComplete="off" :disabled="true" />
      </a-form-item>
    </a-col>
  </a-row>

  <a-collapse v-model:activeKey="vdata.showKey">
    <a-collapse-panel key="map" header="地图选址">
      <div id="amap-container" style="width: 100%; height: 600px">MAP</div>
    </a-collapse-panel>
  </a-collapse>
</template>
<script lang="ts" setup>
import { $getMapConfig } from '@/api/components/GzAmap/index'
import { reactive, ref } from 'vue'
import AMapLoader from '@amap/amap-jsapi-loader'

// emit 父组件使用： v-model="val" 进行双向绑定。
const emit = defineEmits(['update:value', 'change'])

const vdata: any = reactive({
  showKey: 'map',
  mapData: { areacode: [], areacodeNames: [], address: '', lnglat: '' }, //areacode 位置、 省市县、
})

const gzAreaSelect = ref()

// 地图对象
let AMapInstantiate = null as any // 地图实例
let AMapDefine = null as any // 地图定义，初始成功返回的定义对象， 可以通过 AMapDefine.map等获取
let AMapMarker = null as any //标记点
let AutoComplete = null as any //自动录入组件

/** 初始化  */
function init(initMapData) {
  // 清空数据
  vdata.mapData.areacode = initMapData.areacode || []
  vdata.mapData.areacodeNames = initMapData.areacodeNames || []
  vdata.mapData.lnglat = initMapData.lnglat
  vdata.mapData.address = initMapData.address

  AMapInstantiate = null as any // 地图实例
  AMapDefine = null as any // 地图定义，初始成功返回的定义对象， 可以通过 AMapDefine.map等获取
  AMapMarker = null as any //标记点
  AutoComplete = null as any //自动录入组件

  let lnglatArray//初始化地图坐标
  if (initMapData.lnglat) {
    lnglatArray = initMapData.lnglat.split(',')
  } else {
    lnglatArray = [116.397455, 39.909187]//天安门坐标
  }

  // 获取地图配置参数
  $getMapConfig()
    .then((res) => {
      // @ts-ignore window._AMapSecurityConfig
      window._AMapSecurityConfig = { securityJsCode: res.apiMapWebSecret }
      return AMapLoader.load({
        // 申请好的Web端开发者Key，首次调用 load 时必填
        key: res.apiMapWebKey,

        // 指定要加载的 JSAPI 的版本，缺省时默认为 1.4.15
        version: '2.0',

        // 同步加载插件
        plugins: [
          'AMap.ToolBar',
          'AMap.Scale',
          'AMap.Marker',
          'AMap.PlaceSearch',
          'AMap.AutoComplete',
          'AMap.Geocoder',
          'AMap.DistrictSearch',
        ],
      })
    })
    .then((AMap) => {
      // 定义
      AMapDefine = AMap

      // 实例化
      AMapInstantiate = new AMapDefine.Map('amap-container', {
        viewMode: '3D',
        zoom: 15,           //初始化地图级别
        center: [lnglatArray[0], lnglatArray[1]], //初始化地图中心点位置
      })

      AMapInstantiate.addControl(new AMapDefine.ToolBar()) // 工具栏
      AMapInstantiate.addControl(new AMapDefine.Scale()) // 比例尺

      AMapInstantiate.on('complete', function () {
        // 地图图块加载完成后触发
        addMarker(lnglatArray[0], lnglatArray[1])
      })

      // geocoder 地理位置查询插件
      var geocoder = new AMap.Geocoder()

      // 输入提示插件
      AutoComplete = new AMapDefine.AutoComplete({
        input: 'amap-search-input',
        citylimit: true,
      })

      // 搜索到内容后的回调函数
      AutoComplete.on('select', function (e) {
        let name = e.poi.name // 搜索到的名称
        selectLocationFunc(e.poi.location.lng, e.poi.location.lat, name)
      })

      // 地图的选中后的回调函数
      AMapInstantiate.on('click', (e) => {
        // 查询省市县、 位置信息
        geocoder.getAddress(
          new AMapDefine.LngLat(e.lnglat.getLng(), e.lnglat.getLat()),
          function (state, result) {
            // 查找失败
            if (state != 'complete') {
              return false
            }

            // 限制城市搜索
            AutoComplete.setCity(result.regeocode.addressComponent.citycode)

            // 更改省市县  --> 组件调用change事件
            gzAreaSelect.value.changeByAreacode(
              result.regeocode.addressComponent.adcode
            )

            // 选中的点
            selectLocationFunc(
              e.lnglat.getLng(),
              e.lnglat.getLat(),
              result.regeocode.formattedAddress
            )
          }
        )
      })
    })
}

// 选中某个点的事件： 定位到当前地点
function selectLocationFunc(lng, lat, name = null) {
  if (name) {
    vdata.mapData.address = name
  }

  if (!lng || !lat) {
    return false
  }

  // 更改经纬度坐标
  changeInputLnglat(lng, lat)

  // 设置地图中心点
  AMapInstantiate.setCenter(new AMapDefine.LngLat(lng, lat))

  // 添加一个标注点
  addMarker(lng, lat)
}

/**
 * 在地图中添加一个标注点
 */
function addMarker(lng, lat) {
  if (AMapMarker == null) {
    AMapMarker = new AMapDefine.Marker({
      position: new AMapDefine.LngLat(lng, lat)
    })
    AMapInstantiate.add(AMapMarker)
  } else {
    AMapMarker.setPosition(new AMapDefine.LngLat(lng, lat))
  }
}

// 选择省市县的回调函数
function changeAreaCodeFunc(areacode, val) {
  // 无变化
  if (vdata.mapData.areacode && vdata.mapData.areacode[2] == val[2]) {
    return
  }

  // 设置地图的city
  AMapInstantiate.setCity(val[2])

  // 限制城市搜索
  AutoComplete.setCity(val[2])

  //
  vdata.mapData.areacode = val
  vdata.mapData.areacodeNames = [
    areacode[0].label,
    areacode[1].label,
    areacode[2].label,
  ]
}

// 更改输入框的 经纬度
function changeInputLnglat(lng, lat) {
  vdata.mapData.lnglat = lng + ',' + lat
}

function getMapData() {
  return vdata.mapData
}

/**
 * 销毁地图实例
 */
function destroy(){
  if(AMapInstantiate){
    AMapInstantiate.destroy()
  }
  AMapInstantiate = null 
  AMapDefine = null 
  AMapMarker = null
  AutoComplete = null 
}

defineExpose({ init, getMapData,destroy })
</script>

<style scoped>
.right {
  position: relative;
  right: 0px;
  top: 0px;
}
</style>
